/*-------------------------------------------------------------------------
 *
 * pgstrcasecmp.c
 *	   可移植的 SQL 类不区分大小写的比较和转换。
 *
 * SQL99 指定 Unicode 识别的不区分大小写的规范化，而我们还没有基础设施支持。相反，我们使用 tolower() 提供区域设置相关的转换。然而，有一些区域设置在这方面也不正确（例如，土耳其语可能对 'i' 和 'I' 做出奇怪的处理）。我们当前的折衷是对高位设置的字符使用 tolower()，对 7 位字符使用 ASCII 的小写转换。
 *
 * 注意：这段代码应与 scansup.c 中的 downcase_truncate_identifier() 匹配。
 *
 * 我们还提供严格的仅 ASCII 的大小写转换函数，可以用来实现 C/POSIX 的大小写折叠语义，不论 C 库认为区域设置是什么。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 *
 * src/port/pgstrcasecmp.c
 *
 *-------------------------------------------------------------------------
 */
#include "c.h"

#include <ctype.h>


/*
 * 不区分大小写地比较两个以空字符结尾的字符串。
 */
int pg_strcasecmp(const char *fc_s1, const char *fc_s2)
{
	for (;;)
	{
		unsigned char fc_ch1 = (unsigned char) *fc_s1++;
		unsigned char fc_ch2 = (unsigned char) *fc_s2++;

		if (fc_ch1 != fc_ch2)
		{
			if (fc_ch1 >= 'A' && fc_ch1 <= 'Z')
				fc_ch1 += 'a' - 'A';
			else if (IS_HIGHBIT_SET(fc_ch1) && isupper(fc_ch1))
				fc_ch1 = tolower(fc_ch1);

			if (fc_ch2 >= 'A' && fc_ch2 <= 'Z')
				fc_ch2 += 'a' - 'A';
			else if (IS_HIGHBIT_SET(fc_ch2) && isupper(fc_ch2))
				fc_ch2 = tolower(fc_ch2);

			if (fc_ch1 != fc_ch2)
				return (int) fc_ch1 - (int) fc_ch2;
		}
		if (fc_ch1 == 0)
			break;
	}
	return 0;
}

/*
 * 不区分大小写地比较两个不一定以空字符结尾的字符串。
 * 每个字符串最多将检查 n 字节。
 */
int pg_strncasecmp(const char *fc_s1, const char *fc_s2, size_t fc_n)
{
	while (fc_n-- > 0)
	{
		unsigned char fc_ch1 = (unsigned char) *fc_s1++;
		unsigned char fc_ch2 = (unsigned char) *fc_s2++;

		if (fc_ch1 != fc_ch2)
		{
			if (fc_ch1 >= 'A' && fc_ch1 <= 'Z')
				fc_ch1 += 'a' - 'A';
			else if (IS_HIGHBIT_SET(fc_ch1) && isupper(fc_ch1))
				fc_ch1 = tolower(fc_ch1);

			if (fc_ch2 >= 'A' && fc_ch2 <= 'Z')
				fc_ch2 += 'a' - 'A';
			else if (IS_HIGHBIT_SET(fc_ch2) && isupper(fc_ch2))
				fc_ch2 = tolower(fc_ch2);

			if (fc_ch1 != fc_ch2)
				return (int) fc_ch1 - (int) fc_ch2;
		}
		if (fc_ch1 == 0)
			break;
	}
	return 0;
}

/*
 * 将字符转换为大写。
 *
 * 与某些版本的 toupper() 不同，这个函数可以安全地应用于
 * 不是小写字母的字符。请注意，对于多字节字符集来说，
 * 整个过程有点不靠谱。
 */
unsigned char pg_toupper(unsigned char fc_ch)
{
	if (fc_ch >= 'a' && fc_ch <= 'z')
		fc_ch += 'A' - 'a';
	else if (IS_HIGHBIT_SET(fc_ch) && islower(fc_ch))
		fc_ch = toupper(fc_ch);
	return fc_ch;
}

/*
 * 将字符转换为小写。
 *
 * 与某些版本的 tolower() 不同，这个函数可以安全地应用于
 * 不是大写字母的字符。请注意，对于多字节字符集来说，
 * 整个过程有点不靠谱。
 */
unsigned char pg_tolower(unsigned char fc_ch)
{
	if (fc_ch >= 'A' && fc_ch <= 'Z')
		fc_ch += 'a' - 'A';
	else if (IS_HIGHBIT_SET(fc_ch) && isupper(fc_ch))
		fc_ch = tolower(fc_ch);
	return fc_ch;
}

/*
 * 将字符转换为大写，遵循 C/POSIX 区域设置规则。
 */
unsigned char pg_ascii_toupper(unsigned char fc_ch)
{
	if (fc_ch >= 'a' && fc_ch <= 'z')
		fc_ch += 'A' - 'a';
	return fc_ch;
}

/*
 * 将字符转换为小写，遵循 C/POSIX 区域设置规则。
 */
unsigned char pg_ascii_tolower(unsigned char fc_ch)
{
	if (fc_ch >= 'A' && fc_ch <= 'Z')
		fc_ch += 'a' - 'A';
	return fc_ch;
}
